﻿using System.Runtime.InteropServices;

namespace TCommon.Extension;
/// <summary>
/// 结构体拓展
/// </summary>
public static class StructExtension
{
    /// <summary>
    /// 结构体转byte数组
    /// </summary>
    /// <param name="data">数据对象</param>
    /// <returns></returns>
    public static OperateResult<byte[]> StructToBytes(this object data)
    {
        var type = data.GetType();
        if (type is { IsValueType: true, IsEnum: false, IsPrimitive: false }) 
        {
            return OperateResult.CreateFailedResult<byte[]>($"类型{type.Name}非结构体类型");
        }

        IntPtr? ptr = null;
        try
        {
            //计算对象长度
            int iAryLen = Marshal.SizeOf(data);
            //根据长度定义一个数组
            byte[] databytes = new byte[iAryLen];

            //在非托管内存中分配一段iAryLen大小的空间
            ptr = Marshal.AllocHGlobal(iAryLen);
            //将托管内存的东西发送给非托管内存上
            Marshal.StructureToPtr(data, (IntPtr)ptr, true);
            //将bytes组数Copy到Ptr对应的空间中
            Marshal.Copy((IntPtr)ptr, databytes, 0, iAryLen);
            return OperateResult.CreateSuccessResult(databytes);
        }
        catch (Exception e)
        {
            return OperateResult.CreateFailedResult<byte[]>($"转换异常:{e}");
        }
        finally
        {
            if (ptr != null)
            {
                Marshal.FreeHGlobal((IntPtr)ptr);
            }
        }
    }
    /// <summary>
    /// 从byte[]转为struct
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static OperateResult<T> BytesToStruct<T>(this byte[] bytes)
    {
        var type = typeof(T);
        if (type is { IsValueType: true, IsEnum: false, IsPrimitive: false })
        {
            return OperateResult.CreateFailedResult<T>($"类型{type.Name}非结构体类型");
        }

        IntPtr? ptr = null;
        try
        {
            var size = Marshal.SizeOf(type);
            ptr = Marshal.AllocHGlobal(size);
            Marshal.Copy(bytes, 0, (IntPtr)ptr, size);
            var structure = Marshal.PtrToStructure<T>((IntPtr)ptr);
            if (structure != null)
            {
                return OperateResult.CreateSuccessResult<T>(structure);
            }
            else
            {
                return OperateResult.CreateFailedResult<T>("转换失败");
            }
        }
        catch (Exception e)
        {
            return OperateResult.CreateFailedResult<T>($"转换异常:{e}");
        }
        finally
        {
            if (ptr != null)
            {
                Marshal.FreeHGlobal((IntPtr)ptr);
            }
        }
    }
}